vtd: interrupt remapping: be more defensive
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 24 Feb 2010 10:59:37 +0000 (10:59 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 24 Feb 2010 10:59:37 +0000 (10:59 +0000)
1) A buggy BIOS may not report IOAPIC in DRHD. Currently we still try
to enable IR while the IOAPIC RTEs are still in non-remappable format
and the host would hang. The patch detects this case and will not try
to enable IR.

2) Currently HPET's MSI mode doesn't work if IR is enabled because we
have no code to allocate IRTE for it. Luckily this HW configuration is
rather rarely at present, we can just work it around by only using
HPET's IOAPIC mode for now.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
xen/arch/x86/hpet.c
xen/drivers/passthrough/vtd/iommu.c

index 556d1ee10db4707dc6aabccb18a9d2daedb1f9d1..c330a3c82f5c9a0fa981f597da3e646154993115 100644 (file)
@@ -380,6 +380,14 @@ static int hpet_fsb_cap_lookup(void)
     unsigned int num_chs, num_chs_used;
     int i;
 
+    /* TODO. */
+    if ( iommu_intremap )
+    {
+        printk(XENLOG_INFO "HPET's MSI mode hasn't been supported when "
+            "Interrupt Remapping is enabled.\n");
+        return 0;
+    }
+
     id = hpet_read32(HPET_ID);
 
     num_chs = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
index bf325a8d5fcb37bb1a3091828f31fbf7e41cc722..fd77b014baa2e49e7f40a3926fb4dd7fb4fdb0ae 100644 (file)
@@ -1825,6 +1825,23 @@ static int init_vtd_hw(void)
         }
     }
 
+    if ( iommu_intremap )
+    {
+        int apic;
+        for ( apic = 0; apic < nr_ioapics; apic++ )
+        {
+            if ( ioapic_to_iommu(IO_APIC_ID(apic)) == NULL )
+            {
+                iommu_intremap = 0;
+                dprintk(XENLOG_ERR VTDPREFIX,
+                    "ioapic_to_iommu: ioapic 0x%x (id: 0x%x) is NULL! "
+                    "Will not try to enable Interrupt Remapping.\n",
+                    apic, IO_APIC_ID(apic));
+                break;
+            }
+        }
+    }
+
     if ( iommu_intremap )
     {
         for_each_drhd_unit ( drhd )